/***************************************************************************
 *   Copyright (C) 2007 by Ziman & Xloverin                                *
 *   ziman@centrum.sk, xloverin@gmail.com                                  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
 
#include <QSqlQuery>
#include <QVariant>
#include <QStringList>
#include <QMap>
#include <QHash>

#include "tagcache.h"

inline bool TagCache::tagMayMatch(const QString &plain, Line::Type typeHint, const Entry &e, bool BEL)
{
	return
			// Ak mame typeHint, tak ostatne typy uz ignorujeme
			(typeHint == Line::Unknown || typeHint == e.tag.type)
				  
			// Gossip uvazujeme len vtedy, ak typeHint == Gossip
			&& (typeHint == Line::Gossip || e.tag.type != Line::Gossip)
				  
			// Say uvazujeme len vtedy, ak typeHint == Say
			&& (typeHint == Line::Say || e.tag.type != Line::Say)
				  
			// Shout uvazujeme len vtedy, ak typeHint == Shout
			&& (typeHint == Line::Shout || e.tag.type != Line::Shout)
				  
			// Login uvazujeme iba ak mame BEL (tj. bud mame BEL alebo zvazovany typ nie je Login)
			&& (BEL || e.tag.type != Line::Login)
				  
			// ...a, samozrejme, iba ked matchuje regex
			&& e.re.indexIn(plain) > -1;
}

Line::Tag TagCache::getTag(const QString &plain, Line::Type typeHint, bool BEL)
{
	QList<int> &list = types[typeHint];
	
	//qDebug("Tagging[Hint: %s]: '%s'", Line::typeNames[typeHint], plain.toAscii().replace('\n', "").data());
	int count = list.count();
	for (int i = 0; i < count; ++i) {
		Entry &e = entries[list[i]];
		
		if (tagMayMatch(plain, typeHint, e, BEL)) {
			/* Got match! */
			Line::Tag result = e.tag;
						
			//qDebug("Tag[%s]: '%s'", Line::typeNames[result.type], plain.toAscii().replace('\n', "").data());
			QStringList matches = e.re.capturedTexts();
			for (int i = 1; i < matches.count() && i < 4; ++i) {
				// qDebug("arg[%d] == '%s'", i-1, matches[i].toAscii().data());
				result.arg[i-1] = matches[i];
			}
			
			return result;
		}
	}
	
	// Return unknown
	return Line::Tag();
}

TagCache::TagCache()
{
	// Create the reverse tag map
	QHash<QString, int> typeTags;
	for (unsigned i = 0; i < LINE_TYPE_COUNT; ++i) {
		typeTags[Line::typeNames[i]] = i;
	}
	
	// Load the tags from DB
	QSqlQuery query;
	
	// Tu je ORDER BY dolezity -- zarucuje, ze emoty (subtype -1) sa namatchuju az ako posledne
	query.exec("SELECT type, subtype, regex FROM line_tags ORDER BY subtype DESC");
	while (query.next()) {
		Entry entry;
		
		// Construct the entry
		entry.tag.type = (Line::Type) typeTags[query.value(0).toString()];
		entry.tag.subtype = query.value(1).toInt();
		entry.re = QRegExp("^" + query.value(2).toString() + ".*\n$");
		
		// Calculate the index
		int index = entries.count();
		// Add the item to the general list
		entries.append(entry);
		// Add a reference to the corresponding type-separated list
		types[entry.tag.type].append(index);
		// Unknown bude obsahovat zoznam vsetkych entries
		types[Line::Unknown].append(index);
	}	
}


TagCache::~TagCache()
{
}

